﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Globalization;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using Kaiser.Attributes;


namespace Kaiser.Utils
{
    public static class EntityHelper
    {

        public static DataTable RowToColumn<TEnum, TType, TProperty>(Expression<Func<TType, TProperty>> groupBy, List<TType> items, string groupbyColumnCaption, string columnProperty, string valueProperty)
            where TEnum : struct
            where TType : class
        {
            var dt = new DataTable();
            var groupByColunmName = ((MemberExpression)groupBy.Body).Member.Name;
            var properties = typeof(TType).GetProperties().ToList();


            //添加分组属性的数据类型，用于显示的时候序列化
            var tmp = properties.First(property => property.Name == groupByColunmName);
            dt.Columns.Add(new DataColumn(tmp.Name) { Caption = groupbyColumnCaption, DataType = tmp.PropertyType });

            EnumHelper.GetValueAndDescriptionsInt<TEnum>().ForEach(item =>
            {
                {
                    if (item.Value != null)
                        dt.Columns.Add(new DataColumn(item.Key.ToString(CultureInfo.InvariantCulture)) { Caption = item.Value });
                }
            });
            items.GroupBy(groupBy.Compile())
                 .ToList()
                 .ForEach(data =>
                 {
                     var dr = dt.NewRow();
                     data.ToList().ForEach(item =>
                     {
                         var groupByColunm = properties.FirstOrDefault(property => property.Name == groupByColunmName);
                         var column = properties.FirstOrDefault(property => property.Name == columnProperty);
                         var value = properties.FirstOrDefault(property => property.Name == valueProperty);
                         if (column == null) return;
                         var columnValue = column.GetValue(item, null);
                         if (groupByColunm != null)
                         {
                             dr[groupByColunmName] = groupByColunm.GetValue(item, null).ToString();
                         }
                         if (columnValue != null && dt.Columns.Contains(columnValue.ToString()))
                             dr[columnValue.ToString()] = value == null || value.GetValue(item, null) == null ? string.Empty : value.GetValue(item, null).ToString();
                     });
                     dt.Rows.Add(dr);
                 });
            return dt;
        }

 

        private static string FixDefaultValue(object obj) {
            if (obj == null)
                return string.Empty;
            if (obj.ToString() == default(decimal).ToString())
                return string.Empty;
            if (obj.ToString() == default(DateTime).ToString())
                return string.Empty;
            return obj.ToString();
        }

        private static bool  IsFullRow(PropertyInfo info) {
            var attribute = info.GetCustomAttributes(typeof(FullRowAttribute), false);
            return attribute.Length > 0;
        }


        public static string ToString<T>(this IEnumerable<T> items, string str) where T : class
        {

            var builder = new StringBuilder();
            items.ToList().ForEach(item => builder.AppendFormat("{0}{1}", str, item));
            builder.Remove(0, str.Length);
            return builder.ToString();
        }


        /// <summary>
        /// 获取深度资料的结点
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public static List<KeyValuePair<string, InfoNodeAttribute>> GetInfoNodeAttributesRecursion(Type type)
        {
            var list = new List<KeyValuePair<string, InfoNodeAttribute>>();

            type.GetProperties().ToList().ForEach(
                item =>
                {
                    var attributes = item.GetCustomAttributes(typeof(InfoNodeAttribute), false);
                    if (attributes.Length != 0)
                    {
                        list.Add(new KeyValuePair<string, InfoNodeAttribute>(item.Name, (InfoNodeAttribute)attributes[0]));
                    }

                    //递归获取特性
                    if (item.PropertyType.IsClass)
                        list.AddRange(GetInfoNodeAttributesRecursion(item.PropertyType, item.Name));
                });


            return list;
        }


        /// <summary>
        /// 根据父节点获取深度资料的结点
        /// </summary>
        /// <param name="type"></param>
        /// <param name="parentName"></param>
        /// <returns></returns>
        private static List<KeyValuePair<string, InfoNodeAttribute>> GetInfoNodeAttributesRecursion(Type type, string parentName)
        {
            var list = new List<KeyValuePair<string, InfoNodeAttribute>>();

            type.GetProperties().ToList().ForEach(
                item =>
                {
                    var attributes = item.GetCustomAttributes(typeof(InfoNodeAttribute), false);
                    if (attributes.Length != 0)
                    {
                        var attr = (InfoNodeAttribute)attributes[0];
                        attr.Parent = parentName;
                        list.Add(new KeyValuePair<string, InfoNodeAttribute>(item.Name, attr));


                        //递归获取特性
                        if (item.PropertyType.IsClass)
                            list.AddRange(GetInfoNodeAttributesRecursion(item.PropertyType, item.Name));
                    }
                });


            return list;
        }
 

        /// <summary>
        /// 获取待选范围的全部配置
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public static List<KeyValuePair<string, DescriptionEnumAttribute>> GetNodeRangeAttributesRecursion(Type type)
        {
            var list = new List<KeyValuePair<string, DescriptionEnumAttribute>>();

            type.GetProperties().ToList().ForEach(
                item =>
                {
                    var attributes = item.GetCustomAttributes(typeof(DescriptionEnumAttribute), false);
                    if (attributes.Length != 0)
                        list.Add(new KeyValuePair<string, DescriptionEnumAttribute>(item.Name, (DescriptionEnumAttribute)attributes[0]));
                    //递归获取特性
                    if (item.PropertyType.IsEnum)
                        list.AddRange(GetNodeRangeAttributesRecursion(item.PropertyType, item.Name));
                });


            return list;
        }

        /// <summary>
        /// 根据父节点获取待选范围的全部配置
        /// </summary>
        /// <param name="type"></param>
        /// <param name="parentName"></param>
        /// <returns></returns>
        private static List<KeyValuePair<string, DescriptionEnumAttribute>> GetNodeRangeAttributesRecursion(Type type, string parentName)
        {
            var list = new List<KeyValuePair<string, DescriptionEnumAttribute>>();

            type.GetFields().ToList().ForEach(
                item =>
                {
                    var attributes = item.GetCustomAttributes(typeof(DescriptionEnumAttribute), false);
                    if (attributes.Length != 0)
                    {
                        var attr = (DescriptionEnumAttribute)attributes[0];
                        attr.ParentName = parentName;
                        attr.Value = (int)Enum.Parse(type, item.Name);
                        list.Add(new KeyValuePair<string, DescriptionEnumAttribute>(item.Name, attr));
                    }
                });


            return list;
        }


        /// <summary>
        /// 递归获取类的属性的特性集合
        /// </summary>
        /// <typeparam name="TAttribute"></typeparam>
        /// <param name="type"></param>
        /// <returns></returns>
        public static List<TAttribute> GetAttributesRecursion<TAttribute>(Type type)
            where TAttribute : Attribute
        {
            var list = new List<TAttribute>();

            type.GetProperties().ToList().ForEach(
                item =>
                {
                    var attributes = item.GetCustomAttributes(typeof(TAttribute), false);
                    if (attributes.Length != 0)
                        list.Add((TAttribute)attributes[0]);
                    //递归获取特性
                    if (item.ReflectedType.IsClass)
                        list.AddRange(GetAttributesRecursion<TAttribute>(item.PropertyType));
                });


            return list;
        }

        /// <summary>
        /// 不递归获取类的特性的集合
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <typeparam name="TAttribute"></typeparam>
        /// <param name="type"></param>
        /// <returns></returns>
        public static List<TAttribute> GetAttributes<TEntity, TAttribute>()
            where TEntity : class
            where TAttribute : Attribute
        {
            return typeof(TEntity).GetProperties().Select(
               item =>
               {
                   var attributes = item.GetCustomAttributes(typeof(TAttribute), false);
                   if (attributes.Length != 0)
                       return (TAttribute)attributes[0];
                   return null;
               }).Where(item => item != null).ToList();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <typeparam name="TAttribute"></typeparam>
        /// <returns>key为属性的名字</returns>
        public static List<KeyValuePair<string, TAttribute>> GetAttributesDict<TEntity, TAttribute>()
            where TEntity : class
            where TAttribute : Attribute
        {
            return typeof(TEntity).GetProperties().Select(
               item =>
               {
                   var attributes = item.GetCustomAttributes(typeof(TAttribute), false);
                   return new KeyValuePair<string, TAttribute>(item.Name, attributes.Length != 0?(TAttribute)attributes[0]:null);
               }).Where(item => item.Value != null).ToList();
        }

        public static TAttribute GetAttribute<TEntity, TAttribute>(string propertyName)
            where TEntity : class
            where TAttribute : Attribute
        {
            return typeof(TEntity).GetProperties()
                                 .Where(item => item.Name == propertyName)
                                 .Select(item =>
                                 {
                                     var attributes = item.GetCustomAttributes(typeof(TAttribute), false);
                                     if (attributes.Length != 0)
                                         return (TAttribute)attributes[0];
                                     return default(TAttribute);
                                 }).First();
        }

        /// <summary>
        /// 获取给定属性的特性
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <typeparam name="TProperty"></typeparam>
        /// <typeparam name="TAttribute"></typeparam>
        /// <param name="expression">属性表达式</param>
        /// <returns></returns>
        public static TAttribute GetAttribute<TEntity, TProperty, TAttribute>(Expression<Func<TEntity, TProperty>> expression)
            where TEntity : class
            where TAttribute : Attribute
        {
            var memberExpression = expression.Body as MemberExpression;
            return typeof(TEntity).GetProperties()
                                  .Where(item => memberExpression != null && item.Name == memberExpression.Member.Name)
                                  .Select(item =>
                                  {
                                      var attributes = item.GetCustomAttributes(typeof(TAttribute), false);
                                      if (attributes.Length != 0)
                                          return (TAttribute)attributes[0];
                                      return default(TAttribute);
                                  }).First();
        }

    }
}
